﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.SqlClient;
using System.Linq;
using System.Reflection;
using System.Text;
using WW.NActiveRecord.ConnectionAdapters.SqlServer;
using WW.NActiveRecord.Internal;
using WW.NActiveRecord.Internal.SqlFragments;
using WW.NActiveRecord.Internal.Utils;

namespace WW.NActiveRecord {
    public class EntitySet<TEntity> :IEntityMember, IEnumerable<TEntity> where TEntity : Base<TEntity>,new() {
        private List<string> selects = new List<string>();

        //{alias:table}
        private Dictionary<string, string> froms = new Dictionary<string, string>();

        private List<WhereFragment> whereFragments = new List<WhereFragment>();

        private List<JoinFragment> joinFragments = new List<JoinFragment>();

        private string orderBy;

        private string groupBy;

        internal EntityMember entityMember = new EntityMember();

        //查询结果,惰性初始化变量
        private IEnumerable<TEntity> queryResult = null;

        
        private EntitySet() { }

        internal static EntitySet<TEntity> NewByTable(string tableName,string alias) {
            return new EntitySet<TEntity>()
                .From(tableName, alias)
                .Select(string.Format("{0}.*", alias));
        }

        //定义为实体成员集合

        public void Init(FieldInfo fieldInfo, Entity owner) {
            entityMember.Init(fieldInfo, owner);
        }

        public EntitySet<TEntity> Select(params string[] columns) {
            var result = Clone();
            result.selects = new List<string>(columns);
            return result;
        }

        public EntitySet<TEntity> SelectMore(params string[] columns) {
            var result = Clone();
            result.selects.AddRange(columns);
            return result;
        }

        public EntitySet<TEntity> From(string table) {
            string alias = table;
            return From(table, alias);
        }

        /// <summary>
        /// 在Sql中添加更多的From表,用Func<string, string>表达式的参数名和返回值构成表的别名和表名: 
        /// 
        ///  Product.All.From(c => "Categories");
        ///  => SELECT Products.* FROM Products,Categories AS c
        /// 
        ///  Product.All.From(c => "Categories", s => "Suppliers");
        ///  =>SELECT Products.* FROM Products,Categories AS c,Suppliers AS s
        /// </summary>
        /// <param name="tables">加入from子句的表</param>
        /// <returns>实体集合本身</returns>
        // todo from(x=>X.All.Where("xxx")) 查询嵌套
        public EntitySet<TEntity> From(params Func<string, string>[] tables) {
            var result = Clone();
            foreach (var table in tables){
                var p= NamedParameter.NewDynamicParameter(table);
                result.froms.Add(p.Name,(string) p.Value);
            }
            return result;
        }

        /// <summary>
        /// sql where 条件片断
        /// </summary>
        /// <param name="sqlConditionFragment"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public EntitySet<TEntity> Where(string sqlConditionFragment, params Func<string, object>[] parameters) {
            var result = Clone();
            var sqlParameters=parameters.Select(callback => NamedParameter.NewDynamicParameter(callback));
            result.whereFragments.Add(WhereFragment.NewSqlWhereFragment(sqlConditionFragment, sqlParameters));
            return result;
        }

        /// <summary>
        /// 字段查询
        /// </summary>
        /// <param name="fields"></param>
        /// <returns></returns>
        public EntitySet<TEntity> Where(params Func<string, object>[] fields) {
            var result = Clone();
            result.whereFragments.AddRange(fields.Select(f => WhereFragment.NewFieldWhereFragment(NamedParameter.NewDynamicParameter(f))));
            return result;
        }

 

        //TODO Having
        public EntitySet<TEntity> Having(string sqlConditionFragment, params Func<string, object>[] parameters) {
            throw new NotImplementedException();
        }


        //TODO INCLUDE
        public EntitySet<TEntity> Include(params Func<TEntity, object>[] func) {
            return Clone();
        }

        public EntitySet<TEntity> LeftJoin(Func<string, string> alias_Table, string onCondition) {
            var result = Clone();
            var namedParameter = NamedParameter.NewDynamicParameter(alias_Table);
            string alias = namedParameter.Name;
            string table = (string) namedParameter.Value; 
            result.joinFragments.Add(new JoinFragment(table, alias, onCondition));
            return result;
        }

         
        public override string ToString() {
            return Sql();
        }

        
        public string Sql() {
            return SqlDb.Format(CreateCommand());
        }

        public DbCommand Command() {
            return CreateCommand();
        }

        private SqlCommand CreateCommand() {
            var result = new SqlCommand();
            var commandText = new StringBuilder();

            commandText.Append(string.Format("SELECT {0} FROM {1}", selects.JoinString(), ToSqlFroms().JoinString()));

            if (joinFragments.Count() > 0) {
                foreach (var join in joinFragments) {
                    commandText.Append(string.Format(" LEFT JOIN {0} ON {1}", ToSqlAS(join.table, join.alias), join.condition));
                }
            }

            if (whereFragments.Count > 0) {
                var wheres=  whereFragments.Select(whereFragment => whereFragment.Calculate());
                commandText.Append(string.Format(" WHERE {0}", wheres.Select(x => x.sql).JoinString(" AND ")));
                foreach (var where in wheres) {
                    foreach (var parameter in where.parameters) {
                        result.Parameters.AddWithValue(parameter.Key, parameter.Value);
                    }
                }
            }

            if (groupBy != null) {
                commandText.Append(string.Format(" GROUP BY {0}", groupBy));
            }

            if (orderBy != null) {
                commandText.Append(string.Format(" ORDER BY {0}", orderBy));
            }

            result.CommandText=commandText.ToString();
            return result;
        }

        internal EntitySet<TEntity> From(string table, string alias) {
            var result = Clone();
            result.froms.Add(alias,table);
            return result;
        }

        internal EntitySet<TEntity> Where(string columnName,object value){
            var result = Clone();
            WhereFragment f = WhereFragment.NewFieldWhereFragment(NamedParameter.NewFixedParameter(columnName, value));
            result.whereFragments.Add(f);
            return result; 
        }

        public EntitySet<TEntity> OrderBy(string orderBy) {
            var result = Clone();
            result.orderBy = orderBy;
            return result;
        }

        public EntitySet<TEntity> GroupBy(string groupBy) {
            var result = Clone();
            result.groupBy = groupBy;
            return result;
        }

        //public Query<TEntity> ReadOnly(){
        //    throw new NotImplementedException();
        //}



        //public Query<TEntity> Limit(){
        //    throw new NotImplementedException();
        //}

        //public Query<TEntity> Offset(){
        //    throw new NotImplementedException();
        //}

        //public Query<TEntity> Lock(){
        //    throw new NotImplementedException();
        //}

        //public Query<TEntity> Include<TIncludeEntity>(Func<TIncludeEntity, object[]> func){
        //    throw new NotImplementedException();
        //}

        //public Query<TEntity> Include<TIncludeEntity>(params Func<TIncludeEntity, object>[] func){
        //    throw new NotImplementedException();
        //}

        //public Query<TEntity> Include(params string[] includes){
        //    throw new NotImplementedException();
        //}


        #region IEnumerable<TEntity> 成员

        
        public IEnumerator<TEntity> GetEnumerator() {
            //TODO 惰性初始化后保存查询结果
            if (queryResult==null){
                queryResult = Base<TEntity>.FindByCommand(CreateCommand());
            }
            return queryResult.GetEnumerator();
        }

        #endregion

        #region IEnumerable 成员

        IEnumerator IEnumerable.GetEnumerator() {
            return GetEnumerator();
        }

        #endregion

        //From({alias:table})

        private List<string> ToSqlFroms() {
            return froms.Select(alias_table => ToSqlAS(alias_table.Value, alias_table.Key)).ToList();
        }

        private static string ToSqlAS(string table, string alias) {
            return table == alias ? table : string.Format("{0} AS {1}", table, alias);
        }

        private EntitySet<TEntity> Clone() {
            return new EntitySet<TEntity> {
                entityMember = entityMember,
                selects = new List<string>(selects),
                froms = new Dictionary<string, string>(froms),
                joinFragments = new List<JoinFragment>(joinFragments),
                whereFragments = new List<WhereFragment>(whereFragments),
                orderBy = orderBy,
                groupBy = groupBy
            };
        }

        
    }
     
    
}
